// SPDX-FileCopyrightText: 2025 UnionTech Software Technology Co., Ltd.
// SPDX-License-Identifier: MIT

package config

import (
	"encoding/json"
	"flag"
	"fmt"
	"os"
	"path/filepath"
	"strings"
	"time"

	"gopkg.in/yaml.v3"

	"uos_uwsgi_exporter/pkg/errors"
	"uos_uwsgi_exporter/pkg/utils"
)

// Config 配置结构体
type Config struct {
	Address     string
	Port        int
	MetricsPath string
	ConfigFile  string
	ShowVersion bool
	LoadDefault bool // 是否强制加载默认配置文件

	// uWSGI 配置
	Sockets     []string
	SocketTypes map[string]string

	// 日志配置
	LogLevel  string `yaml:"log_level" json:"log_level"`
	LogFile   string `yaml:"log_file" json:"log_file"`
	LogFormat string `yaml:"log_format" json:"log_format"` // json, text

	// 限流配置
	RateLimit int

	// 收集器配置
	SocketTimeout     time.Duration
	CollectionTimeout time.Duration
	MaxConcurrency    int
}

// ParseFlags 解析命令行参数
func ParseFlags() *Config {
	cfg := &Config{}

	// 基础配置
	flag.StringVar(&cfg.Address, "address", "0.0.0.0", "监听地址")
	flag.IntVar(&cfg.Port, "port", 9070, "监听端口")
	flag.StringVar(&cfg.MetricsPath, "metrics-path", "/metrics", "指标路径")
	flag.StringVar(&cfg.ConfigFile, "config", "", "配置文件路径")
	flag.BoolVar(&cfg.ShowVersion, "version", false, "显示版本信息")
	flag.BoolVar(&cfg.LoadDefault, "load-default", false, "强制加载默认配置文件")

	// 日志配置
	flag.StringVar(&cfg.LogLevel, "log-level", "info", "日志级别 (debug, info, warn, error)")
	flag.StringVar(&cfg.LogFile, "log-file", "", "日志文件路径 (为空则输出到控制台)")
	flag.StringVar(&cfg.LogFormat, "log-format", "text", "日志格式 (text, json)")

	// 限流配置
	flag.IntVar(&cfg.RateLimit, "rate-limit", 100, "每秒请求限制")

	// 收集器配置
	var socketTimeout, collectionTimeout string
	flag.StringVar(&socketTimeout, "socket-timeout", "10s", "单个socket连接超时时间")
	flag.StringVar(&collectionTimeout, "collection-timeout", "30s", "整体收集超时时间")
	flag.IntVar(&cfg.MaxConcurrency, "max-concurrency", 10, "最大并发收集数")

	// uWSGI socket 配置
	var sockets string
	flag.StringVar(&sockets, "sockets", "", "uWSGI socket列表，逗号分隔")

	flag.Parse()

	// 处理 socket 配置
	if sockets != "" {
		cfg.Sockets = parseCommaSeparated(sockets)
	}

	// 解析超时配置
	var err error
	if cfg.SocketTimeout, err = time.ParseDuration(socketTimeout); err != nil {
		fmt.Printf("Invalid socket timeout '%s', using default 10s: %v\n", socketTimeout, err)
		cfg.SocketTimeout = 10 * time.Second
	}
	if cfg.CollectionTimeout, err = time.ParseDuration(collectionTimeout); err != nil {
		fmt.Printf("Invalid collection timeout '%s', using default 30s: %v\n", collectionTimeout, err)
		cfg.CollectionTimeout = 30 * time.Second
	}

	// 设置默认值
	if cfg.MaxConcurrency <= 0 {
		cfg.MaxConcurrency = 10
	}

	// 设置默认 socket 类型
	cfg.SocketTypes = make(map[string]string)

	// 加载配置文件
	if err := cfg.loadConfiguration(); err != nil {
		fmt.Printf("Error loading configuration: %v\n", err)
		os.Exit(1)
	}

	// 验证配置
	if err := cfg.Validate(); err != nil {
		fmt.Printf("Configuration validation failed: %v\n", err)
		os.Exit(1)
	}

	return cfg
}

// loadConfiguration 加载配置，支持混合配置
func (c *Config) loadConfiguration() error {
	// 如果命令行指定了配置文件，优先使用
	if c.ConfigFile != "" {
		return c.loadFromFile(c.ConfigFile)
	}

	// 检查是否需要加载默认配置文件
	shouldLoadDefault := c.shouldLoadDefaultConfig()

	if shouldLoadDefault {
		defaultConfigPath := "config/example.yaml"
		if err := c.loadFromFile(defaultConfigPath); err != nil {
			// 如果默认配置文件不存在或读取失败，使用默认值
			fmt.Printf("Warning: Could not load default config file %s: %v\n", defaultConfigPath, err)
			return nil
		}
		fmt.Printf("Info: Loaded configuration from %s\n", defaultConfigPath)
	}

	return nil
}

// shouldLoadDefaultConfig 检查是否应该加载默认配置文件
func (c *Config) shouldLoadDefaultConfig() bool {
	// 总是尝试加载默认配置文件，让命令行参数覆盖配置文件中的值
	return true
}

// hasCustomArguments 检查是否有命令行参数覆盖了默认值
func (c *Config) hasCustomArguments() bool {
	// 检查是否有非默认值的参数
	if c.Address != "0.0.0.0" || c.Port != 9070 || c.MetricsPath != "/metrics" ||
		c.LogLevel != "info" || c.RateLimit != 100 || len(c.Sockets) > 0 {
		return true
	}
	return false
}

// parseCommaSeparated 解析逗号分隔的字符串
func parseCommaSeparated(s string) []string {
	if s == "" {
		return []string{}
	}

	var result []string
	for _, item := range strings.Split(s, ",") {
		if trimmed := strings.TrimSpace(item); trimmed != "" {
			result = append(result, trimmed)
		}
	}
	return result
}

// loadFromFile 从文件加载配置
func (c *Config) loadFromFile(filePath string) error {
	// 检查文件是否存在
	if _, err := os.Stat(filePath); os.IsNotExist(err) {
		return errors.NewConfigFileError(filePath, nil)
	}

	// 读取文件内容
	content, err := os.ReadFile(filePath)
	if err != nil {
		return errors.NewConfigFileError(filePath, err)
	}

	// 根据文件扩展名决定解析方式
	ext := strings.ToLower(filepath.Ext(filePath))
	switch ext {
	case ".yaml", ".yml":
		return c.loadFromYAML(content)
	case ".json":
		return c.loadFromJSON(content)
	default:
		return errors.NewConfigFileError(filePath, fmt.Errorf("unsupported format %s (supported: .yaml, .yml, .json)", ext))
	}
}

// loadFromYAML 从YAML内容加载配置
func (c *Config) loadFromYAML(content []byte) error {
	var configData map[string]interface{}
	if err := yaml.Unmarshal(content, &configData); err != nil {
		return errors.NewParserError("YAML", string(content), err)
	}

	return c.applyConfigData(configData)
}

// loadFromJSON 从JSON内容加载配置
func (c *Config) loadFromJSON(content []byte) error {
	var configData map[string]interface{}
	if err := json.Unmarshal(content, &configData); err != nil {
		return errors.NewParserError("JSON", string(content), err)
	}

	return c.applyConfigData(configData)
}

// applyConfigData 应用配置数据到Config结构体，支持混合配置
func (c *Config) applyConfigData(data map[string]interface{}) error {
	// 处理服务器配置
	if server, ok := data["server"].(map[string]interface{}); ok {
		if v, ok := server["address"].(string); ok && v != "" && c.Address == "0.0.0.0" {
			c.Address = v
		}
		if v, ok := server["port"]; ok && c.Port == 9070 {
			switch port := v.(type) {
			case int:
				if port > 0 {
					c.Port = port
				}
			case float64:
				if port > 0 {
					c.Port = int(port)
				}
			}
		}
		if v, ok := server["metrics_path"].(string); ok && v != "" && c.MetricsPath == "/metrics" {
			c.MetricsPath = v
		}
	}

	// 处理uWSGI配置
	if uwsgi, ok := data["uwsgi"].(map[string]interface{}); ok {
		if v, ok := uwsgi["sockets"].([]interface{}); ok && len(c.Sockets) == 0 {
			var sockets []string
			for _, socket := range v {
				if s, ok := socket.(string); ok && s != "" {
					sockets = append(sockets, s)
				}
			}
			if len(sockets) > 0 {
				c.Sockets = sockets
			}
		}

		if v, ok := uwsgi["socket_types"].(map[string]interface{}); ok {
			if c.SocketTypes == nil {
				c.SocketTypes = make(map[string]string)
			}
			for socket, socketType := range v {
				if s, ok := socketType.(string); ok {
					c.SocketTypes[socket] = s
				}
			}
		}
	}

	// 处理日志配置
	if logging, ok := data["logging"].(map[string]interface{}); ok {
		if v, ok := logging["level"].(string); ok && v != "" && c.LogLevel == "info" {
			c.LogLevel = v
		}
		if v, ok := logging["file"].(string); ok && v != "" && c.LogFile == "" {
			c.LogFile = v
		}
	}

	// 处理限流配置
	if rateLimit, ok := data["rate_limit"].(map[string]interface{}); ok {
		if v, ok := rateLimit["requests_per_second"]; ok && c.RateLimit == 100 {
			switch rps := v.(type) {
			case int:
				if rps > 0 {
					c.RateLimit = rps
				}
			case float64:
				if rps > 0 {
					c.RateLimit = int(rps)
				}
			}
		}
	}

	// 兼容旧格式的直接配置
	if v, ok := data["address"].(string); ok && v != "" && c.Address == "0.0.0.0" {
		c.Address = v
	}
	if v, ok := data["port"]; ok && c.Port == 9070 {
		switch port := v.(type) {
		case int:
			if port > 0 {
				c.Port = port
			}
		case float64:
			if port > 0 {
				c.Port = int(port)
			}
		}
	}
	if v, ok := data["metrics_path"].(string); ok && v != "" && c.MetricsPath == "/metrics" {
		c.MetricsPath = v
	}
	if v, ok := data["log_level"].(string); ok && v != "" && c.LogLevel == "info" {
		c.LogLevel = v
	}
	if v, ok := data["log_file"].(string); ok && v != "" && c.LogFile == "" {
		c.LogFile = v
	}
	if v, ok := data["rate_limit"]; ok && c.RateLimit == 100 {
		switch rateLimit := v.(type) {
		case int:
			if rateLimit > 0 {
				c.RateLimit = rateLimit
			}
		case float64:
			if rateLimit > 0 {
				c.RateLimit = int(rateLimit)
			}
		}
	}
	if v, ok := data["sockets"].([]interface{}); ok && len(c.Sockets) == 0 {
		var sockets []string
		for _, socket := range v {
			if s, ok := socket.(string); ok && s != "" {
				sockets = append(sockets, s)
			}
		}
		if len(sockets) > 0 {
			c.Sockets = sockets
		}
	}
	if v, ok := data["socket_types"].(map[string]interface{}); ok {
		if c.SocketTypes == nil {
			c.SocketTypes = make(map[string]string)
		}
		for socket, socketType := range v {
			if s, ok := socketType.(string); ok {
				c.SocketTypes[socket] = s
			}
		}
	}

	return nil
}

// validateRangeWithDefault 验证值是否在指定范围内，不在范围内时设置默认值或返回错误
func validateRangeWithDefault(field string, value, min, max, defaultValue int) (int, error) {
	if value < min {
		if defaultValue >= min && defaultValue <= max {
			return defaultValue, nil
		}
		return value, errors.NewValidationError(field, fmt.Sprintf("%d", value), fmt.Sprintf("must be >= %d", min)).
			WithContext("current_value", value).
			WithContext("minimum_value", min)
	}
	if value > max {
		return value, errors.NewValidationError(field, fmt.Sprintf("%d", value), fmt.Sprintf("must be <= %d", max)).
			WithContext("current_value", value).
			WithContext("maximum_value", max)
	}
	return value, nil
}

// validateTimeoutWithDefault 验证超时值，设置默认值
func validateTimeoutWithDefault(field string, value, maxValue, defaultValue time.Duration) (time.Duration, error) {
	if value <= 0 {
		return defaultValue, nil
	}
	if value > maxValue {
		return value, errors.NewValidationError(field, value.String(), "too large").
			WithContext("current_value", value).
			WithContext("maximum_value", maxValue.String())
	}
	return value, nil
}

// Validate 验证配置
func (c *Config) Validate() error {
	// 验证端口范围
	if c.Port < 1 || c.Port > 65535 {
		return errors.NewValidationError("port", fmt.Sprintf("%d", c.Port), "must be between 1-65535").
			WithContext("current_value", c.Port).
			WithContext("valid_range", "1-65535")
	}

	// 验证socket配置
	if len(c.Sockets) == 0 {
		return errors.NewConfigError("sockets", "empty", "at least one uWSGI socket must be configured").
			WithContext("configured_sockets", len(c.Sockets))
	}

	// 验证日志级别（如果未设置，使用默认值）
	if c.LogLevel == "" {
		c.LogLevel = "info"
	}
	validLogLevels := map[string]bool{
		"debug": true,
		"info":  true,
		"warn":  true,
		"error": true,
	}
	if !validLogLevels[c.LogLevel] {
		return errors.NewValidationError("log_level", c.LogLevel, "must be one of: debug, info, warn, error").
			WithContext("current_value", c.LogLevel).
			WithContext("valid_values", []string{"debug", "info", "warn", "error"})
	}

	// 验证限流配置（允许0，拒绝负数）
	if c.RateLimit < 0 {
		return errors.NewValidationError("rate_limit", fmt.Sprintf("%d", c.RateLimit), "must not be negative").
			WithContext("current_value", c.RateLimit).
			WithContext("minimum_value", 0)
	}
	// 注意：RateLimit = 0 是有效的，表示禁用限流

	// 验证socket超时配置
	var err error
	if c.SocketTimeout, err = validateTimeoutWithDefault("socket_timeout", c.SocketTimeout, 60*time.Second, 10*time.Second); err != nil {
		return err
	}

	// 验证收集超时配置
	if c.CollectionTimeout, err = validateTimeoutWithDefault("collection_timeout", c.CollectionTimeout, 300*time.Second, 30*time.Second); err != nil {
		return err
	}

	// 验证并发数配置
	if c.MaxConcurrency, err = validateRangeWithDefault("max_concurrency", c.MaxConcurrency, 1, 100, 10); err != nil {
		return err
	}

	return nil
}

// GetConfigSummary 获取配置摘要信息（包含安全脱敏）
func (c *Config) GetConfigSummary() string {
	// 脱敏socket路径
	sanitizedSockets := make([]string, len(c.Sockets))
	for i, socket := range c.Sockets {
		sanitizedSockets[i] = utils.SanitizePath(socket)
	}

	return fmt.Sprintf(
		"Address: %s, Port: %d, MetricsPath: %s, LogLevel: %s, RateLimit: %d, Sockets: %v",
		c.Address, c.Port, c.MetricsPath, c.LogLevel, c.RateLimit, sanitizedSockets,
	)
}

// HasSocketType 检查指定socket是否有类型配置
func (c *Config) HasSocketType(socket string) bool {
	_, exists := c.SocketTypes[socket]
	return exists
}

// GetSocketType 获取指定socket的类型，如果没有配置则返回默认类型
func (c *Config) GetSocketType(socket string) string {
	if socketType, exists := c.SocketTypes[socket]; exists {
		return socketType
	}

	// 使用统一的socket类型检测
	if utils.IsUnixSocket(socket) {
		return "unix"
	}
	return "tcp"
}
